lib/commit: Fix object sizes metadata for multiple commits
authorDan Nicholson <nicholson@endlessm.com>
Wed, 23 Oct 2019 15:12:08 +0000 (09:12 -0600)
committerDan Nicholson <nicholson@endlessm.com>
Tue, 21 Jan 2020 03:42:27 +0000 (20:42 -0700)
The object sizes hash table was only being cleared when the repo was
finalized. That means that performing multiple commits while the repo
was open would reuse all the object sizes metadata for each commit.

Clear the hash table when the sizes metadata is setup and when it's
added to a commit. This still does not fix the issue all the way since
it does nothing to prevent the program from constructing multiple
commits simultaneously. To handle that, the object sizes hash table
should be attached to the MutableTree since that has the commit state.
However, the MutableTree is gone when the commit is actually created.
The hash table would have to be transferred to the root file when
writing the MutableTree. That would be an awkward addition to
OstreeRepoFile, though. Add a FIXME to capture that.

src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo-private.h

index 8f059e117d0ed32bd707e0cc69baddeac329c094..752a01be9f8a8b1e929643f2e9988a227a116966 100644 (file)
@@ -352,7 +352,13 @@ repo_setup_generate_sizes (OstreeRepo               *self,
   if (modifier && modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES)
     {
       if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_ARCHIVE)
-        self->generate_sizes = TRUE;
+        {
+          self->generate_sizes = TRUE;
+
+          /* Clear any stale data in the object sizes hash table */
+          if (self->object_sizes != NULL)
+            g_hash_table_remove_all (self->object_sizes);
+        }
       else
         g_debug ("Not generating sizes for non-archive repo");
     }
@@ -428,6 +434,9 @@ add_size_index_to_metadata (OstreeRepo        *self,
 
       g_variant_builder_add (builder, "{sv}", "ostree.sizes",
                              g_variant_builder_end (&index_builder));
+
+      /* Clear the object sizes hash table for a subsequent commit. */
+      g_hash_table_remove_all (self->object_sizes);
     }
 
   return g_variant_ref_sink (g_variant_builder_end (builder));
index b57ad799f734c4c08775c1d76f04b4580928c7dc..bc2325e56ff372c22a2628b54b0ee90da4d8b09c 100644 (file)
@@ -143,6 +143,14 @@ struct OstreeRepo {
   guint zlib_compression_level;
   GHashTable *loose_object_devino_hash;
   GHashTable *updated_uncompressed_dirs;
+
+  /* FIXME: The object sizes hash table is really per-commit state, not repo
+   * state. Using a single table for the repo means that commits cannot be
+   * built simultaneously if they're adding size information. This data should
+   * probably be in OstreeMutableTree, but that's gone by the time the actual
+   * commit is constructed. At that point the only commit state is in the root
+   * OstreeRepoFile.
+   */
   GHashTable *object_sizes;
 
   /* Cache the repo's device/inode to use for comparisons elsewhere */